package com.laizhenghua.share.device.emqx.handler.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.laizhenghua.rabbit.constant.MqConst;
import com.laizhenghua.rabbit.service.RabbitService;
import com.laizhenghua.share.common.core.constant.DeviceConstants;
import com.laizhenghua.share.device.constant.PowerBankStatus;
import com.laizhenghua.share.device.domain.entity.Cabinet;
import com.laizhenghua.share.device.domain.entity.CabinetSlot;
import com.laizhenghua.share.device.domain.entity.PowerBank;
import com.laizhenghua.share.device.domain.entity.Station;
import com.laizhenghua.share.device.emqx.annotation.DistEmqx;
import com.laizhenghua.share.device.emqx.constant.EmqxConstants;
import com.laizhenghua.share.device.emqx.handler.MassageHandler;
import com.laizhenghua.share.device.service.ICabinetService;
import com.laizhenghua.share.device.service.ICabinetSlotService;
import com.laizhenghua.share.device.service.IPowerBankService;
import com.laizhenghua.share.device.service.IStationService;
import com.laizhenghua.share.order.api.domain.vo.EndOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@DistEmqx(topic = EmqxConstants.TOPIC_POWERBANK_CONNECTED)
public class PowerBankConnectedHandler implements MassageHandler {

    @Autowired
    private ICabinetService cabinetService;

    @Autowired
    private IPowerBankService powerBankService;

    @Autowired
    private ICabinetSlotService cabinetSlotService;

    @Autowired
    private IStationService stationService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    /**
     * 处理消息:
     *  充电宝插入柜机，连接上线，有两种情况
     *      1， 无订单，初始化插入
     *      2， 有订单，归还充电宝
     * @param message
     * {"messageNo":"112233","cabinetNo":"xgxgxxxg","powerBankNo":"gg001",
     * "slotNo":"1", "electricity": 85}
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void handleMessage(JSONObject message) {
        // 1 获取messageNo，防止重复提交
        String messageNo = message.getString("mNo");
        String key = "powerBank:connected:" + messageNo;
        Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(key, messageNo, 1, TimeUnit.HOURS);
        if (Boolean.FALSE.equals(ifAbsent)) {
            return;
        }
        // 2 获取cabinetNo  powerBankNo  slotNo  electricity
        // 柜机编号
        String cabinetNo = message.getString("cNo");
        // 充电宝编号
        String powerBankNo = message.getString("pNo");
        // 插槽编号
        String slotNo = message.getString("sNo");
        // 当前电量
        BigDecimal electricity = message.getBigDecimal("ety");
        // 3 非空判断
        if (StrUtil.isEmpty(cabinetNo) || StrUtil.isEmpty(powerBankNo) || StrUtil.isEmpty(slotNo) || null == electricity) {
            log.info("参数为空: {}", message.toJSONString());
            return;
        }
        // 4 获取相关数据 柜机、充电宝、插槽数据
        Cabinet cabinet = cabinetService.getCabinetByNo(cabinetNo);
        // 获取充电宝
        PowerBank powerBank = powerBankService.getByPowerBankNo(powerBankNo);
        // 获取插槽
        CabinetSlot cabinetSlot = cabinetSlotService.getBtSlotNo(cabinet.getId(), slotNo);
        // 5 更新充电宝数据（电量、状态）
        powerBank.setElectricity(electricity);
        // 电量大于可用最低值
        if (electricity.subtract(DeviceConstants.ELECTRICITY_MIN).doubleValue() > 0) {
            // 可以借用
            powerBank.setStatus(PowerBankStatus.K.getStatus());
        } else {
            // 充电中
            powerBank.setStatus(PowerBankStatus.C.getStatus());
        }
        powerBankService.updateById(powerBank);

        // 6 更新柜机、插槽
        // 更新插槽状态
        cabinetSlot.setPowerBankId(powerBank.getId());
        cabinetSlot.setStatus("1"); // 占用状态？ 插槽无法共用？弹出的充电宝只能放回原来的插槽
        cabinetSlot.setUpdateTime(new Date());
        cabinetSlotService.updateById(cabinetSlot);

        // 更新柜机信息
        int freeSlots = cabinet.getFreeSlots() - 1;
        cabinet.setFreeSlots(freeSlots);
        int usedSlots = cabinet.getUsedSlots() + 1;
        cabinet.setUsedSlots(usedSlots);

        // 可以借用
        if (PowerBankStatus.K.getStatus().equals(powerBank.getStatus())) {
            int availableNum = cabinet.getAvailableNum() - 1;
            cabinet.setAvailableNum(availableNum);
        }
        cabinet.setUpdateTime(new Date());
        cabinetService.updateById(cabinet);

        // 7 rabbit mq 异步生产订单
        EndOrderVo endOrderVo = new EndOrderVo();
        endOrderVo.setMessageNo(messageNo);
        endOrderVo.setEndTime(new Date());
        endOrderVo.setEndCabinetNo(cabinetNo);
        LambdaQueryWrapper<Station> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Station::getCabinetId, cabinet.getId());
        Station station = stationService.getOne(wrapper);
        endOrderVo.setEndStationId(station.getId());
        endOrderVo.setEndStationName(station.getName());
        endOrderVo.setPowerBankNo(powerBankNo);
        rabbitService.sendMessage(MqConst.EXCHANGE_ORDER, MqConst.ROUTING_END_ORDER, JSONObject.toJSONString(endOrderVo));
    }
}

